﻿/*
 * Game Online Project 
 * Version 1.0.0.2
 * Copy right (c) Pham Quang Viet, Bui Minh Long, Uong Thanh Ngoc, Nguyen Khanh Ly
 * All rights reserved.
 *  
 * Module: Server
 * Last update: November 2nd, 2008
 * 
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.IO;
using System.Collections.ObjectModel;

namespace MMOG
{
    enum MessageType : int
    {
        Normal = 0,
        Error = 1,
        Report = 2,
        System = 3
    }

    static class Server
    {
        public static string version = "1.0.0.2";
        public static string lastUpdate = "November 2nd, 2008";

        private static int PORT = 29889;
        public static ServerGUI gui;
        public static Collection<CoreHandler> handlerList;
        public static Collection<RoomInfo> roomList;

        public static bool exited = false;

        public static int runningTime = 0;
        public static int userOnline = 0;
        public static int bugReported = 0;
        public static int errorSinceStart = 0;
        public static int fatalError = 0;
        public static int databaseStatus = 0;
        public static int serverStatus = 0;

        public static int roomId = 0;

        public static bool debugMode = true;
        public static bool errorMode = false;

        //Declare a delegate to avoid cross-access from multi threads
        public delegate void DlgAddLog(String log, MessageType msType);
        public delegate void DlgAddList(String name);
        public delegate void DlgRemoveList(String name);

        public static void addLog(String log, MessageType msType)
        {
            if (gui.logBox.InvokeRequired)
            {
                DlgAddLog dlg = new DlgAddLog(addLog);
                gui.logBox.Invoke(dlg, log, msType);
            }
            else
            {
                gui.logBox.SelectionAlignment = HorizontalAlignment.Left;
                log += "\n";
                switch (msType)
                {
                    case MessageType.Report:
                        log = "Report/> " + log;
                        gui.logBox.SelectionColor = System.Drawing.Color.Orange;
                        break;
                    case MessageType.Normal:
                        log = "Message/> " + log;
                        gui.logBox.SelectionColor = System.Drawing.Color.White;
                        break;
                    case MessageType.Error:
                        log = "Error/> " + log;
                        gui.logBox.SelectionColor = System.Drawing.Color.Red;
                        break;
                    case MessageType.System:
                        log = "System/> " + log;
                        gui.logBox.SelectionColor = System.Drawing.Color.LightGreen;
                        break;
                }
                gui.logBox.AppendText(log);
            }
        }

        public static void addList(String name)
        {
            if (gui.playerList.InvokeRequired)
            {
                DlgAddList dlg = new DlgAddList(addList);
                gui.playerList.Invoke(dlg, name);
            }
            else
                gui.playerList.Items.Add(name);
        }

        public static void removeList(String name)
        {
            if (gui.playerList.InvokeRequired)
            {
                DlgRemoveList dlg = new DlgRemoveList(removeList);
                gui.playerList.Invoke(dlg, name);
            }
            else
                gui.playerList.Items.Remove(name);
        }

        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            //Create and show the user interface for the server
            gui = new ServerGUI();
            gui.Show();

            //Add copy right information
            gui.logBox.SelectionAlignment = HorizontalAlignment.Center;
            gui.logBox.SelectionColor = System.Drawing.Color.Gold;
            gui.logBox.AppendText(
                "VersusOnline server (v" + version + ")\n"
                + "Copy right(c) 2008 vietpq, ngocut, longbm, lynk"
                + "\n------\n"
            );

            //Initialize database
            databaseStatus = Database.init();
            if (databaseStatus == 0) gui.databaseLabel.Text = "Online";
            else
            {
                gui.databaseLabel.Text = "Error(" + databaseStatus + ")";
                addLog("Database offline, game cannot be started", MessageType.Error);
            }

            try
            {
                //Start the TCP/IP Server
                IPAddress local = IPAddress.Parse("127.0.0.1");
                TcpListener listener = new TcpListener(local, PORT);
                listener.Start();

                addLog("Listening to port: [" + PORT+"]", MessageType.System);

                handlerList = new Collection<CoreHandler>();
                roomList = new Collection<RoomInfo>();                

                while (true)
                {

                    //Wait and accept incoming connection
                    if (listener.Pending())
                    {
                        CoreHandler coreHandler = new CoreHandler(listener.AcceptTcpClient());
                        //Create a new thread to handle the incoming connection
                        Thread newClient = new Thread(new ThreadStart(coreHandler.run));
                        addLog(coreHandler.client.Client.RemoteEndPoint.ToString()+": Connection established!",MessageType.Report);
                        newClient.IsBackground = true;
                        newClient.Start();
                    }

                    //Save processing time for other processes
                    Thread.Sleep(30);

                    //Process events
                    Application.DoEvents();

                    //If exited flag was set
                    if (exited)
                    {
                        listener.Stop();
                        Application.Exit();
                        return;
                    }
                }
            }
            catch (SocketException)
            {
                gui.logBox.AppendText("Socket exception!\n");
            }
            catch (Exception)
            {
                gui.logBox.AppendText("Unknown exception!\n");
            }
            while (true)
            {
                Thread.Sleep(100);
                Application.DoEvents();
                if (exited) Application.Exit();
            }
        }
    }
}
